Preparation
Load statistical test function
#### ---------------- testchi2 ----------------
#' @title Compute the average salience of the topic and test significance of deviation
#' @name what
#' @description create a table and graphic of the topic
#' @param tabtest a table with variable trial, success and null.value
#' @param minsamp : Threshold of sample size requested for salience computation
#' @param mintest : Threshold of estimated value requested for chi-square test
testchi2<-function(tabtest=tabtest,
minsamp = 20,
mintest = 5)
{
tab<-tabtest
n<-dim(tab)[1]
# Compute salience if sample size sufficient (default : N>20)
tab$estimate <-NA
tab$salience <-NA
tab$chi2<-NA
tab$p.value<-NA
tab$estimate<-round(tab$success/tab$trial,5)
tab$salience<-tab$estimate/tab$null.value
# Chi-square test if estimated value sufficient (default : Nij* > 5)
for (i in 1:n) {
if(tab$trial[i]*tab$null.value[i]>=mintest) {
test<-prop.test(x=tab$success[i],n=tab$trial[i], p=tab$null.value[i],
alternative = "greater")
tab$chi2[i]<-round(test$statistic,2)
tab$p.value[i]<-round(test$p.value,5)
}
}
# }
return(tab)
}
What
Function
### ---------------- what ----------------
#' @title Compute the average salience of the topic
#' @name what
#' @description create a table and graphic of the topic
#' @param hc an hypercube prepared as data.table
#' @param subtop a subtag of the main tag (default = NA)
#' @param title Title of the graphic
what <- function (hc = hypercube,
what = "what",
subtop = NA,
title = "What ?")
{
tab<-hc
tab$what<-tab[[what]]
if (is.na(subtop)){tab$what <-tab$what !="_no_"}else {tab$what <- tab$what == subtop}
tab<-tab[,list(news = sum(news)),by = what]
tab$pct<-100*tab$news/sum(tab$news)
p <- plot_ly(tab,
labels = ~what,
values = ~pct,
type = 'pie') %>%
layout(title = title,
xaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE),
yaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE))
output<-list("table" = tab, "plotly" =p)
return(output)
}
Application 1 : covid topic
res<-what(hc_year)
res$table
res$plotly
Application n°2 : state subtopic
res <-hc_year %>% filter(states != "_no_") %>%
what(what = "states",
subtop ="RUS",
title = "Share of Russia in international news")
res$table
res$plotly
Application n°3 : macroregion subtopic
res <-hc_year %>% filter(regions != "_no_") %>%
what(what = "regions",
subtop ="OR_EU",
title = "Share of EU in macroregional news")
res$table
res$plotly
Who.What
function
#### ---------------- who.what ----------------
#' @title visualize variation of the topic between media
#' @name who.what
#' @description create a table of variation of the topic by media
#' @param hc an hypercube prepared as data.table
#' @param test : visualize test (TRUE) or salience (FALSE)
#' @param minsamp : Threshold of sample size requested for salience computation
#' @param mintest sample size of estimate for chi-square test (default = 5)
#' @param title Title of the graphic
who.what <- function (hc = hypercube,
what = "what",
subtop = NA,
test = FALSE,
minsamp = 20,
mintest = 5,
title = "Who says What ?")
{
tab<-hc
tab$what<-tab[[what]]
if (is.na(subtop)){tab$what <-tab$what !="_no_"}else {tab$what <- tab$what == subtop}
# {tab$what <-tab$what !="_no_"}
tab<-tab[,list(trial = sum(news),success=round(sum(news*what),0)),by = list(who)]
ref <-round(sum(tab$success)/sum(tab$trial),4)
tab$null.value<-ref
tab<-testchi2(tabtest=tab,
minsamp = minsamp,
mintest = mintest)
if (test==FALSE) {tab$index =tab$salience
tab$index[tab$index>4]<-4
tab<-tab[tab$trial > minsamp,]
mycol<-brewer.pal(7,"YlOrRd")
}
else {tab$index=1-tab$p.value
tab<-tab[tab$trial*tab$null.value>mintest,]
mycol<-rev(brewer.pal(7,"RdYlBu"))
mycol[4]<-"lightyellow"
}
p <- plot_ly(tab,
x = ~who,
y = ~estimate*100,
color= ~index,
colors= mycol,
hovertemplate = ~paste('Source: ',who,
'<br /> Total news : ', round(trial,0),
'<br /> Topic news : ', round(success,0),
'<br /> % observed : ', round(estimate*100,2),'%',
'<br /> % estimated : ', round(null.value*100,2),'%',
'<br /> Salience : ', round(salience,2),
'<br /> p.value : ', round(p.value,4)),
type = "bar") %>%
layout(title = title,
yaxis = list(title = "% news"),
barmode = 'stack')
output<-list("table" = tab, "plotly" =p)
return(output)
}
Applicaton n°1 : Covid Topic
An example of computation of the share of a non spatial topic (Covid)
in the full sample of news.
res <- hc_year %>%
who.what(what = "what",
title = "Share of Covid in total news",
test=FALSE)
res$table
res$plotly
Warning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arrays
Application n°2 : State subtopic
An example of computation of the share of a national subtopic
(Russia) in the sample of news where the topic is present (news with at
least one state mentionned).
res <-hc_year %>% filter(states != "_no_") %>%
who.what(what = "states",
subtop ="RUS",
title = "Share of Russia in international news",
test=TRUE)
res$table
res$plotly
Warning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arrays
Application n°3 : Macroregion subtopic
Same example applied to macroregion : what is the share of the
subtopic European Union in the subsample news where at least one
macroregion is mentionned.
res <-hc_year %>% filter(regions != "_no_") %>%
who.what(what = "regions",
subtop ="OR_EU",
title = "Share of EU in macroregional news",
test=TRUE)
res$table
res$plotly
Warning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arrays
saveWidget(widget=res$plotly,
file = "widgets/widget_who_what.html",
selfcontained = T,
libdir="lib")
Warning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arrays
When.What
function
#### ---------------- when.what ----------------
#' @title visualize variation of the topic through time
#' @name when.what
#' @description create a table of variation of the topic by media
#' @param test : visualize test (TRUE) or salience (FALSE)
#' @param minsamp : Threshold of sample size requested for salience computation
#' @param mintest sample size of estimate for chi-square test (default = 5)
#' @param title Title of the graphic
when.what <- function (hc = hypercube,
what = "what",
subtop = NA,
test = FALSE,
minsamp = 20,
mintest = 5,
title = "When is said What ?")
{
tab<-hc
tab$what<-tab[[what]]
if (is.na(subtop)){tab$what <-tab$what !="_no_"}else {tab$what <- tab$what == subtop}
# {tab$what <-tab$what !="_no_"}
tab<-tab[,list(trial = sum(news),success=round(sum(news*what),0)),by = list(when)]
ref <-round(sum(tab$success)/sum(tab$trial),4)
tab$null.value<-ref
tab<-testchi2(tabtest=tab,
minsamp = minsamp,
mintest = mintest)
if (test==FALSE) {tab$index =tab$salience
tab<-tab[tab$trial > minsamp,]
mycol<-brewer.pal(7,"YlOrRd")
}
else {tab$index=tab$p.value
tab<-tab[tab$trial*tab$null.value>mintest,]
mycol<-brewer.pal(7,"RdYlBu")
mycol[4]<-"lightyellow"
}
p <- plot_ly(tab,
x = ~as.character(when),
y = ~estimate*100,
color= ~index,
colors= mycol,
# hoverinfo = "text",
hovertemplate = ~paste('Time: ',when,
'<br /> Total news : ', round(trial,0),
'<br /> Topic news : ', round(success,0),
'<br /> % observed : ', round(estimate*100,2),'%',
'<br /> % estimated : ', round(null.value*100,2),'%',
'<br /> Salience : ', round(salience,2),
'<br /> p.value : ', round(p.value,4)),
type = "bar") %>%
layout(title = title,
yaxis = list(title = "% news"),
barmode = 'stack')
output<-list("table" = tab, "plotly" =p)
return(output)
}
Applicaton n°1 : Covid Topic
An example of computation of the share of a non spatial topic (Covid)
in the full sample of news by week for one media.
res <- hc_week %>% filter(who=="DEU_suddeu") %>%
when.what(what = "what",
title = "Share of Covid-19 topic in news published by Süddeutsche Zeitung",
test=FALSE)
res$table
res$plotly
Warning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arrays
Application n°2 : State subtopic
Example of analysis of the share of news about Russia among news
mentionning one country, by month, for Le Figaro.
res <-hc_month %>% filter(states != "_no_") %>% filter(who=="FRA_figaro") %>%
when.what(what = "states",
subtop ="RUS",
title = "Share of Russia in international news published by Le Figaro",
test=TRUE)
res$table
res$plotly
Warning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arrays
Application n°3 : Macroregion subtopic
Example of analysis of the share of news about European news among
news mentioning one macroregion, by year, for Dunya.
res <-hc_year %>% filter(regions != "_no_") %>% filter(who=="TUR_dunya") %>%
when.what(what = "regions",
subtop ="OR_EU",
title = "Share of EU in macroregional news published by Dunya",
test=TRUE)
res$table
res$plotly
Warning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arrays
saveWidget(widget=res$plotly,
file = "widgets/widget_who_what.html",
selfcontained = T,
libdir="lib")
Warning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arrays
LS0tCnRpdGxlOiAiR2VvZ3JhcGhpY2FsIGFuYWx5c2lzIG9mIG1lZGlhIgpzdWJ0aXRsZTogIjUuIFdpZGdldHMiCmF1dGhvcjogIkNsYXVkZSBHcmFzbGFuZCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCmBgYHtyIHNldHVwNSwgZWNobyA9IEZBTFNFLCBjb21tZW50ID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGNvbW1lbnQgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShkcGx5cikKbGlicmFyeShrbml0cikKbGlicmFyeShodG1sd2lkZ2V0cykKI2xpYnJhcnkodGlkeWdyYXBoKQojbGlicmFyeShnZ3JhcGgpCiNsaWJyYXJ5KHZpc05ldHdvcmspCmBgYAoKCgojIyBPYmplY3RpdmUKClRoZSBhaW0gb2YgdGhpcyBzZWN0aW9uIGlzIHRvIHByZXNlbnQgdGhlIGRpZmZlcmVudCB3aWRnZXRzIHVzZWQgZm9yIHRoZSBleHBsb3JhdGlvbiBvZiBoeXBlcmN1YmVzIGFuZCBkZXZlbG9wcGVkIGR1cmluZyB0aGUgT0RZQ0NFVVMgcHJvamVjdC4gV2UgYWRhcHQgYSBsaXR0bGUgdGhlIGluaXRpYWwgcHJvZ3JhbXMgZm9yIHRoZSBjYXNlIG9mIG9jdG9jdWJlcyB0aGF0IGFyZSB1c2VkIGluIElNQUdFVU4gYnV0IHRoZSBwcmluY2lwbGVzIHJlbWFpbnMgdGhlIHNhbWUuIEVhY2ggd2lkZ2V0IHdpbGwgZXhwb3J0IGEgZGF0YWZyYW1lIGFuZCBhIHBsb3RseSBmaWd1cmUsIG1ha2luZyBwb3NzaWJsZSB0byBzdG9yZSB0aGUgcmVzdWx0cyBpbiBqYXZhc2NyaXB0IGFuZC9vciB0byB1c2UgdGhlIHRhYmxlIGZvciBkZXZlbG9wbWVudCB3aXRoIGFub3RoZXIgc29mdHdhcmUuCgoKCiMjIFByZXBhcmF0aW9uCgojIyMgTG9hZCBtdWx0aWxldmVsIG9jdG9jdWJlcyBhbmQgdHJhbnNmb3JtIGluIGh5cGVyY3ViZXMKCldlIGxvYWQgdGhlIG9jdG9jdWJlcyBhdCBkaWZmZXJlbnQgbGV2ZWxzIG9mIHRpbWUgYWdyZWdhdGlvbiBhbmQgdHJhbnNmb3JtIHRoZW0gaW4gaHlwZXJjdWJlcyBieSByZW1vdmluZyB0aGUgZHVhbCBkaW1lbnNpb25zIG9mIHN0YXRlcyBhbmQgcmVnaW9ucwoKYGBge3J9CmJhc2U8LXJlYWRSRFMoIm9jdG9jdWJlcy9oY19teWNvcnB1c19jb3ZpZF9zdGF0ZXNfcmVnaW9ucy5SRFMiKQpoY19kYXk8LWJhc2UkZGF5WywuKHRhZz1zdW0odGFncyksbmV3cz1zdW0obmV3cykpLC4od2hvLHdoYXQsd2hlbixzdGF0ZXM9c3RhdGVzMSxyZWdpb25zPXJlZ2lvbnMxKV0KaGNfd2VlazwtYmFzZSR3ZWVrWywuKHRhZz1zdW0odGFncyksbmV3cz1zdW0obmV3cykpLC4od2hvLHdoYXQsd2hlbixzdGF0ZXM9c3RhdGVzMSxyZWdpb25zPXJlZ2lvbnMxKV0KaGNfbW9udGg8LWJhc2UkbW9udGhbLC4odGFnPXN1bSh0YWdzKSxuZXdzPXN1bShuZXdzKSksLih3aG8sd2hhdCx3aGVuLHN0YXRlcz1zdGF0ZXMxLHJlZ2lvbnM9cmVnaW9uczEpXQpoY195ZWFyPC1iYXNlJHllYXJbLC4odGFnPXN1bSh0YWdzKSxuZXdzPXN1bShuZXdzKSksLih3aG8sd2hhdCx3aGVuLHN0YXRlcz1zdGF0ZXMxLHJlZ2lvbnM9cmVnaW9uczEpXQpgYGAKCgojIyMgTG9hZCBzdGF0aXN0aWNhbCB0ZXN0IGZ1bmN0aW9uCgpgYGB7cn0KIyMjIyAtLS0tLS0tLS0tLS0tLS0tIHRlc3RjaGkyIC0tLS0tLS0tLS0tLS0tLS0KIycgQHRpdGxlICBDb21wdXRlIHRoZSBhdmVyYWdlIHNhbGllbmNlIG9mIHRoZSB0b3BpYyBhbmQgdGVzdCBzaWduaWZpY2FuY2Ugb2YgZGV2aWF0aW9uCiMnIEBuYW1lIHdoYXQKIycgQGRlc2NyaXB0aW9uIGNyZWF0ZSBhIHRhYmxlIGFuZCBncmFwaGljIG9mIHRoZSB0b3BpYwojJyBAcGFyYW0gdGFidGVzdCBhIHRhYmxlIHdpdGggdmFyaWFibGUgdHJpYWwsIHN1Y2Nlc3MgYW5kIG51bGwudmFsdWUKIycgQHBhcmFtIG1pbnNhbXAgOiBUaHJlc2hvbGQgb2Ygc2FtcGxlIHNpemUgcmVxdWVzdGVkIGZvciBzYWxpZW5jZSBjb21wdXRhdGlvbgojJyBAcGFyYW0gbWludGVzdCA6IFRocmVzaG9sZCBvZiBlc3RpbWF0ZWQgdmFsdWUgcmVxdWVzdGVkIGZvciBjaGktc3F1YXJlIHRlc3QKCgp0ZXN0Y2hpMjwtZnVuY3Rpb24odGFidGVzdD10YWJ0ZXN0LAogICAgICAgICAgICAgICAgICAgbWluc2FtcCA9IDIwLAogICAgICAgICAgICAgICAgICAgbWludGVzdCA9IDUpIAp7CiAgdGFiPC10YWJ0ZXN0CiAgbjwtZGltKHRhYilbMV0KICAKICAjIENvbXB1dGUgc2FsaWVuY2UgaWYgc2FtcGxlIHNpemUgc3VmZmljaWVudCAoZGVmYXVsdCA6IE4+MjApCiAgdGFiJGVzdGltYXRlIDwtTkEKICB0YWIkc2FsaWVuY2UgPC1OQQogIHRhYiRjaGkyPC1OQQogIHRhYiRwLnZhbHVlPC1OQQogICB0YWIkZXN0aW1hdGU8LXJvdW5kKHRhYiRzdWNjZXNzL3RhYiR0cmlhbCw1KQogICB0YWIkc2FsaWVuY2U8LXRhYiRlc3RpbWF0ZS90YWIkbnVsbC52YWx1ZQogIAogICMgQ2hpLXNxdWFyZSB0ZXN0IGlmIGVzdGltYXRlZCB2YWx1ZSBzdWZmaWNpZW50IChkZWZhdWx0IDogTmlqKiA+IDUpCiAgCiAgZm9yIChpIGluIDE6bikgewogICAgaWYodGFiJHRyaWFsW2ldKnRhYiRudWxsLnZhbHVlW2ldPj1taW50ZXN0KSB7ICAKICAgICAgdGVzdDwtcHJvcC50ZXN0KHg9dGFiJHN1Y2Nlc3NbaV0sbj10YWIkdHJpYWxbaV0sIHA9dGFiJG51bGwudmFsdWVbaV0sIAogICAgICAgICAgICAgICAgICAgICAgYWx0ZXJuYXRpdmUgPSAiZ3JlYXRlciIpCiAgICAgIHRhYiRjaGkyW2ldPC1yb3VuZCh0ZXN0JHN0YXRpc3RpYywyKQogICAgICB0YWIkcC52YWx1ZVtpXTwtcm91bmQodGVzdCRwLnZhbHVlLDUpCiAgICB9IAogIH0KICMgfQogIHJldHVybih0YWIpCn0KCmBgYAoKIyMgV2hhdAoKCiMjIyBGdW5jdGlvbgoKYGBge3J9CiMjIyAtLS0tLS0tLS0tLS0tLS0tIHdoYXQgLS0tLS0tLS0tLS0tLS0tLQojJyBAdGl0bGUgIENvbXB1dGUgdGhlIGF2ZXJhZ2Ugc2FsaWVuY2Ugb2YgdGhlIHRvcGljCiMnIEBuYW1lIHdoYXQKIycgQGRlc2NyaXB0aW9uIGNyZWF0ZSBhIHRhYmxlIGFuZCBncmFwaGljIG9mIHRoZSB0b3BpYwojJyBAcGFyYW0gaGMgYW4gaHlwZXJjdWJlIHByZXBhcmVkIGFzIGRhdGEudGFibGUKIycgQHBhcmFtIHN1YnRvcCBhIHN1YnRhZyBvZiB0aGUgbWFpbiB0YWcgKGRlZmF1bHQgPSBOQSkKIycgQHBhcmFtIHRpdGxlIFRpdGxlIG9mIHRoZSBncmFwaGljCgoKd2hhdCA8LSBmdW5jdGlvbiAoaGMgPSBoeXBlcmN1YmUsCiAgICAgICAgICAgICAgICAgIHdoYXQgPSAid2hhdCIsCiAgICAgICAgICAgICAgICAgIHN1YnRvcCA9IE5BLAogICAgICAgICAgICAgICAgICB0aXRsZSA9ICJXaGF0ID8iKQp7CiAKICAKdGFiPC1oYwp0YWIkd2hhdDwtdGFiW1t3aGF0XV0KaWYgKGlzLm5hKHN1YnRvcCkpe3RhYiR3aGF0IDwtdGFiJHdoYXQgIT0iX25vXyJ9ZWxzZSB7dGFiJHdoYXQgPC0gdGFiJHdoYXQgPT0gc3VidG9wfQoKdGFiPC10YWJbLGxpc3QobmV3cyA9IHN1bShuZXdzKSksYnkgPSB3aGF0XQp0YWIkcGN0PC0xMDAqdGFiJG5ld3Mvc3VtKHRhYiRuZXdzKQoKcCA8LSBwbG90X2x5KHRhYiwKICAgICAgICAgICAgIGxhYmVscyA9IH53aGF0LAogICAgICAgICAgICAgdmFsdWVzID0gfnBjdCwKICAgICAgICAgICAgIHR5cGUgPSAncGllJykgJT4lCiAgbGF5b3V0KHRpdGxlID0gdGl0bGUsCiAgICAgICAgIHhheGlzID0gbGlzdChzaG93Z3JpZCA9IEZBTFNFLCB6ZXJvbGluZSA9IEZBTFNFLCBzaG93dGlja2xhYmVscyA9IEZBTFNFKSwKICAgICAgICAgeWF4aXMgPSBsaXN0KHNob3dncmlkID0gRkFMU0UsIHplcm9saW5lID0gRkFMU0UsIHNob3d0aWNrbGFiZWxzID0gRkFMU0UpKQoKb3V0cHV0PC1saXN0KCJ0YWJsZSIgPSB0YWIsICJwbG90bHkiID1wKQoKcmV0dXJuKG91dHB1dCkKCn0KYGBgCgojIyMgQXBwbGljYXRpb24gMSA6IGNvdmlkIHRvcGljCgoKYGBge3J9CnJlczwtd2hhdChoY195ZWFyKQpyZXMkdGFibGUKcmVzJHBsb3RseQpgYGAKCgojIyMgQXBwbGljYXRpb24gbsKwMiA6IHN0YXRlIHN1YnRvcGljCgpgYGB7cn0KcmVzIDwtaGNfeWVhciAlPiUgZmlsdGVyKHN0YXRlcyAhPSAiX25vXyIpICU+JQp3aGF0KHdoYXQgPSAic3RhdGVzIiwKICAgICBzdWJ0b3AgPSJSVVMiLAogICAgIHRpdGxlID0gIlNoYXJlIG9mIFJ1c3NpYSBpbiBpbnRlcm5hdGlvbmFsIG5ld3MiKQpyZXMkdGFibGUKcmVzJHBsb3RseQpgYGAKCiMjIyBBcHBsaWNhdGlvbiBuwrAzIDogbWFjcm9yZWdpb24gc3VidG9waWMKCmBgYHtyfQpyZXMgPC1oY195ZWFyICU+JSBmaWx0ZXIocmVnaW9ucyAhPSAiX25vXyIpICU+JQp3aGF0KHdoYXQgPSAicmVnaW9ucyIsCiAgICAgc3VidG9wID0iT1JfRVUiLAogICAgIHRpdGxlID0gIlNoYXJlIG9mIEVVIGluIG1hY3JvcmVnaW9uYWwgbmV3cyIpCnJlcyR0YWJsZQpyZXMkcGxvdGx5CmBgYAoKIyMgV2hvLldoYXQKCiMjIyBmdW5jdGlvbgoKYGBge3J9CiMjIyMgLS0tLS0tLS0tLS0tLS0tLSB3aG8ud2hhdCAtLS0tLS0tLS0tLS0tLS0tCiMnIEB0aXRsZSAgdmlzdWFsaXplIHZhcmlhdGlvbiBvZiB0aGUgdG9waWMgYmV0d2VlbiBtZWRpYQojJyBAbmFtZSB3aG8ud2hhdAojJyBAZGVzY3JpcHRpb24gY3JlYXRlIGEgdGFibGUgb2YgdmFyaWF0aW9uIG9mIHRoZSB0b3BpYyBieSBtZWRpYQojJyBAcGFyYW0gaGMgYW4gaHlwZXJjdWJlIHByZXBhcmVkIGFzIGRhdGEudGFibGUKIycgQHBhcmFtIHRlc3QgOiB2aXN1YWxpemUgdGVzdCAoVFJVRSkgb3Igc2FsaWVuY2UgKEZBTFNFKQojJyBAcGFyYW0gbWluc2FtcCA6IFRocmVzaG9sZCBvZiBzYW1wbGUgc2l6ZSByZXF1ZXN0ZWQgZm9yIHNhbGllbmNlIGNvbXB1dGF0aW9uCiMnIEBwYXJhbSBtaW50ZXN0IHNhbXBsZSBzaXplIG9mIGVzdGltYXRlIGZvciBjaGktc3F1YXJlIHRlc3QgKGRlZmF1bHQgPSA1KQojJyBAcGFyYW0gdGl0bGUgVGl0bGUgb2YgdGhlIGdyYXBoaWMKCgp3aG8ud2hhdCA8LSBmdW5jdGlvbiAoaGMgPSBoeXBlcmN1YmUsCiAgICAgICAgICAgICAgICAgICAgICB3aGF0ID0gIndoYXQiLAogICAgICAgICAgICAgICAgICAgICAgc3VidG9wID0gTkEsCiAgICAgICAgICAgICAgICAgICAgICB0ZXN0ID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICBtaW5zYW1wID0gMjAsCiAgICAgICAgICAgICAgICAgICAgICBtaW50ZXN0ID0gNSwKICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIldobyBzYXlzIFdoYXQgPyIpCnsKICAKICB0YWI8LWhjCiAgdGFiJHdoYXQ8LXRhYltbd2hhdF1dCmlmIChpcy5uYShzdWJ0b3ApKXt0YWIkd2hhdCA8LXRhYiR3aGF0ICE9Il9ub18ifWVsc2Uge3RhYiR3aGF0IDwtIHRhYiR3aGF0ID09IHN1YnRvcH0KIyAge3RhYiR3aGF0IDwtdGFiJHdoYXQgIT0iX25vXyJ9CiAgCiAgdGFiPC10YWJbLGxpc3QodHJpYWwgPSBzdW0obmV3cyksc3VjY2Vzcz1yb3VuZChzdW0obmV3cyp3aGF0KSwwKSksYnkgPSBsaXN0KHdobyldCiAgcmVmIDwtcm91bmQoc3VtKHRhYiRzdWNjZXNzKS9zdW0odGFiJHRyaWFsKSw0KQogIHRhYiRudWxsLnZhbHVlPC1yZWYKICAKICB0YWI8LXRlc3RjaGkyKHRhYnRlc3Q9dGFiLAogICAgICAgICAgICAgICAgbWluc2FtcCA9IG1pbnNhbXAsCiAgICAgICAgICAgICAgICBtaW50ZXN0ID0gbWludGVzdCkKICAKICAKICAKICBpZiAodGVzdD09RkFMU0UpIHt0YWIkaW5kZXggPXRhYiRzYWxpZW5jZQogIHRhYiRpbmRleFt0YWIkaW5kZXg+NF08LTQKICB0YWI8LXRhYlt0YWIkdHJpYWwgPiBtaW5zYW1wLF0KICBteWNvbDwtYnJld2VyLnBhbCg3LCJZbE9yUmQiKQogIH0gCiAgZWxzZSB7dGFiJGluZGV4PTEtdGFiJHAudmFsdWUKICB0YWI8LXRhYlt0YWIkdHJpYWwqdGFiJG51bGwudmFsdWU+bWludGVzdCxdCiAgbXljb2w8LXJldihicmV3ZXIucGFsKDcsIlJkWWxCdSIpKQogIG15Y29sWzRdPC0ibGlnaHR5ZWxsb3ciCiAgfQogIAogIHAgPC0gcGxvdF9seSh0YWIsCiAgICAgICAgICAgICAgIHggPSB+d2hvLAogICAgICAgICAgICAgICB5ID0gfmVzdGltYXRlKjEwMCwKICAgICAgICAgICAgICAgY29sb3I9IH5pbmRleCwKICAgICAgICAgICAgICAgY29sb3JzPSBteWNvbCwKICAgICAgICAgICAgICAgaG92ZXJ0ZW1wbGF0ZSA9IH5wYXN0ZSgnU291cmNlOiAnLHdobywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnPGJyIC8+IFRvdGFsIG5ld3MgIDogJywgcm91bmQodHJpYWwsMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzxiciAvPiBUb3BpYyBuZXdzIDogJywgcm91bmQoc3VjY2VzcywwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnPGJyIC8+ICUgb2JzZXJ2ZWQgIDogJywgcm91bmQoZXN0aW1hdGUqMTAwLDIpLCclJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnPGJyIC8+ICUgZXN0aW1hdGVkIDogJywgcm91bmQobnVsbC52YWx1ZSoxMDAsMiksJyUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICc8YnIgLz4gU2FsaWVuY2UgOiAnLCByb3VuZChzYWxpZW5jZSwyKSwgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICc8YnIgLz4gcC52YWx1ZSA6ICcsIHJvdW5kKHAudmFsdWUsNCkpLAogICAgICAgICAgICAgICB0eXBlID0gImJhciIpICAlPiUKICAgIGxheW91dCh0aXRsZSA9IHRpdGxlLAogICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICIlIG5ld3MiKSwKICAgICAgICAgICBiYXJtb2RlID0gJ3N0YWNrJykKICAKICBvdXRwdXQ8LWxpc3QoInRhYmxlIiA9IHRhYiwgInBsb3RseSIgPXApCiAgCiAgcmV0dXJuKG91dHB1dCkKICAKfQpgYGAKCiMjIyBBcHBsaWNhdG9uIG7CsDEgOiBDb3ZpZCBUb3BpYwoKQW4gZXhhbXBsZSBvZiBjb21wdXRhdGlvbiBvZiB0aGUgc2hhcmUgb2YgYSBub24gc3BhdGlhbCB0b3BpYyAoQ292aWQpIGluIHRoZSBmdWxsIHNhbXBsZSBvZiBuZXdzLgoKYGBge3J9CnJlcyA8LSBoY195ZWFyICU+JQp3aG8ud2hhdCh3aGF0ID0gIndoYXQiLAogICAgIHRpdGxlID0gIlNoYXJlIG9mIENvdmlkIGluIHRvdGFsIG5ld3MiLAogICAgIHRlc3Q9RkFMU0UpCgpyZXMkdGFibGUKcmVzJHBsb3RseQpgYGAKCgoKIyMjIEFwcGxpY2F0aW9uIG7CsDIgOiBTdGF0ZSBzdWJ0b3BpYwoKQW4gZXhhbXBsZSBvZiBjb21wdXRhdGlvbiBvZiB0aGUgc2hhcmUgb2YgYSBuYXRpb25hbCBzdWJ0b3BpYyAoUnVzc2lhKSBpbiB0aGUgc2FtcGxlIG9mIG5ld3Mgd2hlcmUgdGhlIHRvcGljIGlzIHByZXNlbnQgKG5ld3Mgd2l0aCBhdCBsZWFzdCBvbmUgc3RhdGUgbWVudGlvbm5lZCkuCgpgYGB7cn0KcmVzIDwtaGNfeWVhciAlPiUgZmlsdGVyKHN0YXRlcyAhPSAiX25vXyIpICU+JQp3aG8ud2hhdCh3aGF0ID0gInN0YXRlcyIsCiAgICAgc3VidG9wID0iUlVTIiwKICAgICB0aXRsZSA9ICJTaGFyZSBvZiBSdXNzaWEgaW4gaW50ZXJuYXRpb25hbCBuZXdzIiwKICAgICB0ZXN0PVRSVUUpCnJlcyR0YWJsZQpyZXMkcGxvdGx5CmBgYAoKIyMjIEFwcGxpY2F0aW9uIG7CsDMgOiBNYWNyb3JlZ2lvbiBzdWJ0b3BpYwoKU2FtZSBleGFtcGxlIGFwcGxpZWQgdG8gbWFjcm9yZWdpb24gOiB3aGF0IGlzIHRoZSBzaGFyZSBvZiB0aGUgc3VidG9waWMgRXVyb3BlYW4gVW5pb24gaW4gdGhlIHN1YnNhbXBsZSBuZXdzIHdoZXJlIGF0IGxlYXN0IG9uZSBtYWNyb3JlZ2lvbiBpcyBtZW50aW9ubmVkLgoKYGBge3J9CnJlcyA8LWhjX3llYXIgJT4lIGZpbHRlcihyZWdpb25zICE9ICJfbm9fIikgJT4lCndoby53aGF0KHdoYXQgPSAicmVnaW9ucyIsCiAgICAgc3VidG9wID0iT1JfRVUiLAogICAgIHRpdGxlID0gIlNoYXJlIG9mIEVVIGluIG1hY3JvcmVnaW9uYWwgbmV3cyIsCiAgICAgdGVzdD1UUlVFKQpyZXMkdGFibGUKcmVzJHBsb3RseQpzYXZlV2lkZ2V0KHdpZGdldD1yZXMkcGxvdGx5LAogICAgICAgICAgIGZpbGUgPSAid2lkZ2V0cy93aWRnZXRfd2hvX3doYXQuaHRtbCIsCiAgICAgICAgICAgc2VsZmNvbnRhaW5lZCA9IFQsCiAgICAgICAgICAgbGliZGlyPSJsaWIiKQpgYGAKCgoKIyMgV2hlbi5XaGF0CgojIyMgZnVuY3Rpb24KYGBge3J9CgojIyMjIC0tLS0tLS0tLS0tLS0tLS0gd2hlbi53aGF0IC0tLS0tLS0tLS0tLS0tLS0KIycgQHRpdGxlICB2aXN1YWxpemUgdmFyaWF0aW9uIG9mIHRoZSB0b3BpYyB0aHJvdWdoIHRpbWUKIycgQG5hbWUgd2hlbi53aGF0CiMnIEBkZXNjcmlwdGlvbiBjcmVhdGUgYSB0YWJsZSBvZiB2YXJpYXRpb24gb2YgdGhlIHRvcGljIGJ5IG1lZGlhCiMnIEBwYXJhbSB0ZXN0IDogdmlzdWFsaXplIHRlc3QgKFRSVUUpIG9yIHNhbGllbmNlIChGQUxTRSkKIycgQHBhcmFtIG1pbnNhbXAgOiBUaHJlc2hvbGQgb2Ygc2FtcGxlIHNpemUgcmVxdWVzdGVkIGZvciBzYWxpZW5jZSBjb21wdXRhdGlvbgojJyBAcGFyYW0gbWludGVzdCBzYW1wbGUgc2l6ZSBvZiBlc3RpbWF0ZSBmb3IgY2hpLXNxdWFyZSB0ZXN0IChkZWZhdWx0ID0gNSkKIycgQHBhcmFtIHRpdGxlIFRpdGxlIG9mIHRoZSBncmFwaGljCgoKd2hlbi53aGF0IDwtIGZ1bmN0aW9uIChoYyA9IGh5cGVyY3ViZSwKICAgICAgICAgICAgICAgICAgICAgICB3aGF0ID0gIndoYXQiLAogICAgICAgICAgICAgICAgICAgICAgIHN1YnRvcCA9IE5BLAogICAgICAgICAgICAgICAgICAgICAgIHRlc3QgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICBtaW5zYW1wID0gMjAsCiAgICAgICAgICAgICAgICAgICAgICAgbWludGVzdCA9IDUsCiAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiV2hlbiBpcyBzYWlkIFdoYXQgPyIpCnsKICAKICB0YWI8LWhjCiAgdGFiJHdoYXQ8LXRhYltbd2hhdF1dCmlmIChpcy5uYShzdWJ0b3ApKXt0YWIkd2hhdCA8LXRhYiR3aGF0ICE9Il9ub18ifWVsc2Uge3RhYiR3aGF0IDwtIHRhYiR3aGF0ID09IHN1YnRvcH0KIyAge3RhYiR3aGF0IDwtdGFiJHdoYXQgIT0iX25vXyJ9CiAgCiAgdGFiPC10YWJbLGxpc3QodHJpYWwgPSBzdW0obmV3cyksc3VjY2Vzcz1yb3VuZChzdW0obmV3cyp3aGF0KSwwKSksYnkgPSBsaXN0KHdoZW4pXQogIHJlZiA8LXJvdW5kKHN1bSh0YWIkc3VjY2Vzcykvc3VtKHRhYiR0cmlhbCksNCkKICB0YWIkbnVsbC52YWx1ZTwtcmVmCiAgCiAgdGFiPC10ZXN0Y2hpMih0YWJ0ZXN0PXRhYiwKICAgICAgICAgICAgICAgIG1pbnNhbXAgPSBtaW5zYW1wLAogICAgICAgICAgICAgICAgbWludGVzdCA9IG1pbnRlc3QpCiAgCiAgaWYgKHRlc3Q9PUZBTFNFKSB7dGFiJGluZGV4ID10YWIkc2FsaWVuY2UKICB0YWI8LXRhYlt0YWIkdHJpYWwgPiBtaW5zYW1wLF0KICBteWNvbDwtYnJld2VyLnBhbCg3LCJZbE9yUmQiKQogIH0gCiAgZWxzZSB7dGFiJGluZGV4PXRhYiRwLnZhbHVlCiAgdGFiPC10YWJbdGFiJHRyaWFsKnRhYiRudWxsLnZhbHVlPm1pbnRlc3QsXQogIG15Y29sPC1icmV3ZXIucGFsKDcsIlJkWWxCdSIpCiAgbXljb2xbNF08LSJsaWdodHllbGxvdyIKICB9CiAgCiAgCiAgcCA8LSBwbG90X2x5KHRhYiwKICAgICAgICAgICAgICAgeCA9IH5hcy5jaGFyYWN0ZXIod2hlbiksCiAgICAgICAgICAgICAgIHkgPSB+ZXN0aW1hdGUqMTAwLAogICAgICAgICAgICAgICBjb2xvcj0gfmluZGV4LAogICAgICAgICAgICAgICBjb2xvcnM9IG15Y29sLAogICAgICMgICAgICAgICAgaG92ZXJpbmZvID0gInRleHQiLAogICAgICAgICAgICAgICBob3ZlcnRlbXBsYXRlID0gfnBhc3RlKCdUaW1lOiAnLHdoZW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzxiciAvPiBUb3RhbCBuZXdzICA6ICcsIHJvdW5kKHRyaWFsLDApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICc8YnIgLz4gVG9waWMgbmV3cyA6ICcsIHJvdW5kKHN1Y2Nlc3MsMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzxiciAvPiAlIG9ic2VydmVkICA6ICcsIHJvdW5kKGVzdGltYXRlKjEwMCwyKSwnJScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzxiciAvPiAlIGVzdGltYXRlZCA6ICcsIHJvdW5kKG51bGwudmFsdWUqMTAwLDIpLCclJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnPGJyIC8+IFNhbGllbmNlIDogJywgcm91bmQoc2FsaWVuY2UsMiksICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnPGJyIC8+IHAudmFsdWUgOiAnLCByb3VuZChwLnZhbHVlLDQpKSwKICAgICAgICAgICAgICAgdHlwZSA9ICJiYXIiKSAgJT4lCiAgICBsYXlvdXQodGl0bGUgPSB0aXRsZSwKICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiJSBuZXdzIiksCiAgICAgICAgICAgYmFybW9kZSA9ICdzdGFjaycpCiAgCiAgb3V0cHV0PC1saXN0KCJ0YWJsZSIgPSB0YWIsICJwbG90bHkiID1wKQogIAogIHJldHVybihvdXRwdXQpCiAgCn0KYGBgCgoKCiMjIyBBcHBsaWNhdG9uIG7CsDEgOiBDb3ZpZCBUb3BpYwoKQW4gZXhhbXBsZSBvZiBjb21wdXRhdGlvbiBvZiB0aGUgc2hhcmUgb2YgYSBub24gc3BhdGlhbCB0b3BpYyAoQ292aWQpIGluIHRoZSBmdWxsIHNhbXBsZSBvZiBuZXdzIGJ5IHdlZWsgZm9yIG9uZSBtZWRpYS4KCmBgYHtyfQpyZXMgPC0gaGNfd2VlayAlPiUgZmlsdGVyKHdobz09IkRFVV9zdWRkZXUiKSAlPiUKd2hlbi53aGF0KHdoYXQgPSAid2hhdCIsCiAgICAgdGl0bGUgPSAiU2hhcmUgb2YgQ292aWQtMTkgdG9waWMgaW4gbmV3cyBwdWJsaXNoZWQgYnkgU8O8ZGRldXRzY2hlIFplaXR1bmciLAogICAgIHRlc3Q9RkFMU0UpCgpyZXMkdGFibGUKcmVzJHBsb3RseQpgYGAKCgoKIyMjIEFwcGxpY2F0aW9uIG7CsDIgOiBTdGF0ZSBzdWJ0b3BpYwoKRXhhbXBsZSBvZiBhbmFseXNpcyBvZiB0aGUgc2hhcmUgb2YgbmV3cyBhYm91dCBSdXNzaWEgYW1vbmcgbmV3cyBtZW50aW9ubmluZyBvbmUgY291bnRyeSwgYnkgbW9udGgsIGZvciBMZSBGaWdhcm8uCgpgYGB7cn0KcmVzIDwtaGNfbW9udGggJT4lIGZpbHRlcihzdGF0ZXMgIT0gIl9ub18iKSAlPiUgIGZpbHRlcih3aG89PSJGUkFfZmlnYXJvIikgJT4lCndoZW4ud2hhdCh3aGF0ID0gInN0YXRlcyIsCiAgICAgc3VidG9wID0iUlVTIiwKICAgICB0aXRsZSA9ICJTaGFyZSBvZiBSdXNzaWEgaW4gaW50ZXJuYXRpb25hbCBuZXdzIHB1Ymxpc2hlZCBieSBMZSBGaWdhcm8iLAogICAgIHRlc3Q9VFJVRSkKcmVzJHRhYmxlCnJlcyRwbG90bHkKYGBgCgojIyMgQXBwbGljYXRpb24gbsKwMyA6IE1hY3JvcmVnaW9uIHN1YnRvcGljCgpFeGFtcGxlIG9mIGFuYWx5c2lzIG9mIHRoZSBzaGFyZSBvZiBuZXdzIGFib3V0IEV1cm9wZWFuIG5ld3MgYW1vbmcgbmV3cyBtZW50aW9uaW5nIG9uZSBtYWNyb3JlZ2lvbiwgYnkgeWVhciwgZm9yIER1bnlhLgoKYGBge3J9CnJlcyA8LWhjX3llYXIgJT4lIGZpbHRlcihyZWdpb25zICE9ICJfbm9fIikgJT4lICBmaWx0ZXIod2hvPT0iVFVSX2R1bnlhIikgJT4lCndoZW4ud2hhdCh3aGF0ID0gInJlZ2lvbnMiLAogICAgIHN1YnRvcCA9Ik9SX0VVIiwKICAgICB0aXRsZSA9ICJTaGFyZSBvZiBFVSBpbiBtYWNyb3JlZ2lvbmFsIG5ld3MgcHVibGlzaGVkIGJ5IER1bnlhIiwKICAgICB0ZXN0PVRSVUUpCnJlcyR0YWJsZQpyZXMkcGxvdGx5CnNhdmVXaWRnZXQod2lkZ2V0PXJlcyRwbG90bHksCiAgICAgICAgICAgZmlsZSA9ICJ3aWRnZXRzL3dpZGdldF93aG9fd2hhdC5odG1sIiwKICAgICAgICAgICBzZWxmY29udGFpbmVkID0gVCwKICAgICAgICAgICBsaWJkaXI9ImxpYiIpCmBgYA==